require "engine.class"
local Chat = require "engine.Chat"
local DamageType = require "engine.DamageType"
local Map = require "engine.Map"
local Target = require "engine.Target"
local Talents = require "engine.interface.ActorTalents"

--- Interface to add ToME combat system
module(..., package.seeall, class.make)

--- Checks what to do with the target
-- Talk ? attack ? displace ?
function _M:bumpInto(target)
	local reaction = self:reactionToward(target)
	if reaction < 0 then
		if self:attr("no_blow") then game.logPlayer(self, "You are unable to attack!")
		else return self:attackTarget(target) end
	elseif reaction >= 0 then
		-- Talk ?
		if self.player and target.can_talk then
			local chat = Chat.new(target.can_talk, target, self)
			chat:invoke()
		elseif target.player and self.can_talk then
			local chat = Chat.new(self.can_talk, self, target)
			chat:invoke()
		-- Displace
		elseif self.move_others then
			game.level.map:remove(self.x, self.y, Map.ACTOR)
			game.level.map:remove(target.x, target.y, Map.ACTOR)
			game.level.map(self.x, self.y, Map.ACTOR, target)
			game.level.map(target.x, target.y, Map.ACTOR, self)
			self.x, self.y, target.x, target.y = target.x, target.y, self.x, self.y
		end
	end
end

--- Makes the death happen!
function _M:attackTarget(target, mult)
	local p = math.pow((self.combat_bonus - 25), 2) / 100
	local adjust = 0.02/math.exp(p)

	if self.combat then
		if self:checkHit(self.combat_atk + self.combat_bonus, target.combat_def) then
			local dam = math.max(0, self.combat.dam + self:getStr() - math.max(0, target.combat_armor - self.combat_apr)) / 15 + self.combat_bonus / 2
			
			-- adjust damage accordingly (crit, mult, or invulnerable)
			if target.invulnerable == true then dam = 0 end
			if mult then dam = dam * mult end
			if rng.chance(20) then
				dam = dam * 2
				game.logSeen(self, "%s performs a critical stike!", self.name:capitalize())
			end
			DamageType:get(self.combat.damtype or DamageType.PHYSICAL).projector(self, target.x, target.y, (self.combat.damtype or DamageType.PHYSICAL), math.max(0, dam))
			self.combat_bonus = self.combat_bonus + adjust
			target.combat_def = target.combat_def + (adjust/20)
		else -- miss code
			local srcname = game.level.map.seens(self.x, self.y) and self.name:capitalize() or "Something"
			game.logSeen(self, "%s misses %s.", srcname, target.name)
			self.combat_bonus = self.combat_bonus + (adjust/10)
			target.combat_def = target.combat_def + (adjust/2)
		end
	end

	if self == game.player then print("[PLAYER COMBAT_BONUS] ", self.combat_bonus)
	else self:useEnergy(game.energy_to_act) end		-- We use up our own energy
end

--- Computes a logarithmic chance to hit, opposing chance to hit to chance to miss
-- This will be used for melee attacks, physical and spell resistance
function _M:checkHit(atk, def, min, max, factor)
	print("checkHit", atk, def)
	if atk == 0 then atk = 1 end
	local hit = nil
	factor = factor or 5
	if atk > def then
		local d = atk - def
		hit = math.log10(1 + 5 * d / 50) * 100 + 50
	else
		local d = def - atk
		hit = -math.log10(1 + 5 * d / 50) * 100 + 50
	end
	hit = util.bound(hit, min or 5, max or 95)
	print("=> chance to hit", hit)
	return rng.percent(hit), hit
end
